/* 
 * File:   common_FirmaDigital.cpp
 * Author: gabilan
 * 
 * Created on 12 de junio de 2013, 19:16
 */

#include <stdlib.h>

#include "common_FirmaDigital.h"

FirmaDigital::FirmaDigital() {
}

void FirmaDigital::GenerarClave64Bytes(const std::string& clave, 
                                      unsigned char* clave64)
{
    if(clave.length() <= TAM_CLAVE)
    {
        for(int i = 0; i< clave.length(); i++)
            clave64[i] = clave[i];
        for(int i = clave.length(); i < TAM_CLAVE; i++)
            clave64[i] = CERO_CHAR;    
    }
    else
    {
        for(int i = 0; i < TAM_CLAVE; i++)
            clave64[i] = clave[i];
    }
}

void FirmaDigital::XORClaveIpad(unsigned char* clave64, unsigned char* ipad)
{
    for(int i = 0; i < TAM_CLAVE; i++)
    {       
        ipad[i] = clave64[i];
        ipad[i] ^= CHAR_IPAD;
    }
}

void FirmaDigital::XORClaveOpad(unsigned char* clave64, unsigned char* opad)
{
    for(int i = 0; i < TAM_CLAVE; i++)
    {       
        opad[i] = clave64[i];
        opad[i] ^= CHAR_OPAD;
    }    
}

void FirmaDigital::AppendIpadBloque(unsigned char* bloque_firmado,unsigned char*
                      ipad, const char* bloque, const size_t tam_bloque_firmado)
{
    for(int i = 0; i < TAM_CLAVE; i++)
        bloque_firmado[i] = ipad[i];
    for(int i = TAM_CLAVE; i < tam_bloque_firmado;i++)
        bloque_firmado[i] = bloque[i-TAM_CLAVE];   
}

void FirmaDigital::AppendOpadHash(unsigned char* bloque_final, unsigned char* 
                                  opad, const char* hash)
{
    int tam = TAM_CLAVE + TAM_HASH;
    for(int i = 0; i < TAM_CLAVE; i++)
        bloque_final[i] = opad[i];
    for(int i = TAM_CLAVE; i < tam; i++)
        bloque_final[i] = hash[i-TAM_CLAVE];   
}

std::string FirmaDigital::FirmaHMAC(const char* bloque,const std::string& clave)
{
    unsigned char* clave64 = new unsigned char[TAM_CLAVE];
    unsigned char* ipad = new unsigned char [TAM_CLAVE];
    unsigned char* opad = new unsigned char[TAM_CLAVE];
    
    this->GenerarClave64Bytes(clave, clave64);
    
    this->XORClaveIpad(clave64, ipad);
    
    //h1 = HASH(ipad + bloque)
    size_t tam_bloque_firmado = TAM_CLAVE + strlen(bloque);
    unsigned char* bloque_firmado = new unsigned char[tam_bloque_firmado];
    this->AppendIpadBloque(bloque_firmado, ipad, bloque, tam_bloque_firmado);
    
    char* hash_bloq_firmado = new char[TAM_HASH];
    calcularHashMD5Bloque((const char*)bloque_firmado, tam_bloque_firmado,
                           hash_bloq_firmado);
    
    this->XORClaveOpad(clave64, opad);
    
    //h2 = (opad + h1) --> h2 es la firma
    size_t tam_bloque_final = TAM_CLAVE + TAM_HASH;
    unsigned char * bloque_final = new unsigned char[tam_bloque_final];
    this->AppendOpadHash(bloque_final, opad, (const char *)hash_bloq_firmado);
    
    char* hash_final = new char[TAM_HASH];
  
    calcularHashMD5Bloque((const char*)bloque_final, strlen((const char*)
                           bloque_final),hash_final);
    
    std::string firma(hash_final);
    delete [] clave64;
    delete [] ipad;
    delete [] opad;
    delete [] bloque_firmado;
    delete [] hash_bloq_firmado;
    delete [] bloque_final;
    delete [] hash_final;
    return firma;
}


FirmaDigital::~FirmaDigital() {
}

